package com.lining.orangeservice.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class JwtUtil {

    // 从配置文件中读取JWT密钥
    @Value("${jwt.secret}")
    private String secret;

    // 从配置文件中读取JWT过期时间（单位：毫秒）
    @Value("${jwt.expiration}")
    private Long expiration;

    // 固定的调试Token，对应admin用户
    private static final String DEBUG_TOKEN = "diting";

    // admin用户的用户名
    private static final String ADMIN_USERNAME = "admin";

    /**
     * 获取签名密钥
     *
     * 使用配置的密钥字符串生成一个HMAC-SHA密钥，用于JWT的签名和验证。
     *
     * @return 用于JWT签名的SecretKey对象
     */
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    /**
     * 生成JWT Token
     *
     * 为指定的用户名和用户ID生成一个JWT Token，包含以下信息：
     * - 用户ID作为自定义声明
     * - 用户名作为主题(subject)
     * - 当前时间为签发时间
     * - 过期时间为当前时间加上配置的过期时间
     *
     * @param username 用户名
     * @param userId 用户ID
     * @return 生成的JWT Token字符串
     */
    public String generateToken(String username, Long userId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 从JWT Token中提取用户名
     *
     * 解析Token并获取其中的subject字段，即用户名。
     *
     * @param token JWT Token字符串
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        if (DEBUG_TOKEN.equals(token)) {
            return ADMIN_USERNAME;
        }
        return getClaimsFromToken(token).getSubject();
    }

    /**
     * 从JWT Token中提取用户ID
     *
     * 解析Token并获取其中的自定义声明"userId"。
     *
     * @param token JWT Token字符串
     * @return 用户ID
     */
    public Long getUserIdFromToken(String token) {
        return getClaimsFromToken(token).get("userId", Long.class);
    }

    /**
     * 获取JWT Token的过期时间
     *
     * 解析Token并获取其中的过期时间字段。
     *
     * @param token JWT Token字符串
     * @return 过期时间Date对象
     */
    public Date getExpirationDateFromToken(String token) {
        return getClaimsFromToken(token).getExpiration();
    }

    /**
     * 验证JWT Token的有效性
     *
     * 尝试解析Token，如果解析成功则认为Token有效，否则无效。
     * 捕获JwtException和IllegalArgumentException异常，记录错误日志。
     *
     * @param token JWT Token字符串
     * @return Token是否有效
     */
    public boolean validateToken(String token) {
        try {
            // 如果是调试Token，则直接返回true
            if (DEBUG_TOKEN.equals(token)) {
                return true;
            }
            getClaimsFromToken(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            log.error("JWT token验证失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 刷新JWT Token
     *
     * 使用旧Token中的信息重新生成一个新的Token，延长其有效期。
     *
     * @param token 原始JWT Token字符串
     * @return 新生成的JWT Token字符串
     */
    public String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        String username = claims.getSubject();
        Long userId = claims.get("userId", Long.class);
        return generateToken(username, userId);
    }

    /**
     * 解析JWT Token获取Claims对象
     *
     * 使用签名密钥解析Token，获取其中的Claims（声明）部分。
     *
     * @param token JWT Token字符串
     * @return Claims对象，包含Token中的所有声明信息
     */
    private Claims getClaimsFromToken(String token) {

        return Jwts.parser()
                .setSigningKey(getSigningKey()) // 设置验证密钥
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 从HTTP请求头中提取JWT Token
     *
     * @param request HTTP请求对象
     * @return 提取到的JWT Token，如果没有则返回null
     */
    public  String getTokenFromRequest(HttpServletRequest request) {
        // 从请求头中获取Authorization字段
        String bearerToken = request.getHeader("Authorization");

        // 检查Authorization字段是否存在且以"Bearer "开头
        // JWT Token通常以"Bearer "作为前缀
        if (bearerToken != null && bearerToken.startsWith("Bearer "))
            // 返回Bearer后面的Token部分（去掉前7个字符"Bearer "）
            return bearerToken.substring(7);
        return null;
    }
}
